/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core\types
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AEVariable.h
// Author:		Gianluca Belardelli
// Date:		21/02/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEVARIABLE_H_
#define _AEVARIABLE_H_

/// \brief
///   This class holds class specific variables in the RTTI system
///
/// Instances of VisVariable_cl are implicitly generated by the DEFINE_VAR_xyz macros. Pointer to a VisVariable_cl are
/// passed to VTypedObject::OnVariableValueChanging and VTypedObject::OnVariableValueChanged to identify variables.
///
/// \sa VTypedObject
class AEVariable
{
// Members
public:
	const char				*m_lpName; ///< Name of the variable
	const char				*m_lpDisplayName;  ///< A string used ONLY for display in Editor
	AEINT32					m_nType;                     ///< Variable type; casted to enum type VulpType_e
	const char				*m_lpDefaultValue;     ///< String that represents the default value, e.g. "0.01"
	const char				*m_lpDesc;             ///< description text for the variable; shown in vForge
	const char				*m_lpCategory;         ///< variable category
	const char				*m_lpEditorHintString; ///< additional property editor definition fro vFOrge. See documentation
	size_t					m_stExtraInfo;   ///< length for strings, opt. for enum.....
	AEINT32					m_nClassOffset;      ///< offset in object class, can be -1 for no update
	VDisplayHintFlags_e		hintFlags;  ///< hint flags for vForge property editors
	AEVariable				*m_lpNextVar;     ///< next linked list entry

	AE_COREDLLIMPEXP static const char *ms_lpActiveCategory; ///< this one temporarily stores the category name
	AE_COREDLLIMPEXP static VisVariableObjectValueConverter *s_pStringToShaderEffectConverter;

// Methods
public:
  VBASE_IMPEXP AEVariable( void );

  /// \brief
  ///   Abstract base class for variable conversion of higher level types.
  ///
  /// Using a converter object in order to perform conversion is necessary if an object can only 
  /// be created on higher levels of abstraction (e.g. shader effects should be created by using 
  /// Vision::Shaders).
  struct VisVariableObjectValueConverter
  {
    // virtual destructor
    virtual ~VisVariableObjectValueConverter(){}

    /// \brief
    ///   Converts from string to the respective variable type.
    ///
    /// \param szStr
    ///   String representation of the object.
    virtual void *StringToObjectValue(const char* szStr) = 0;

    /// \brief
    ///   Converts from the respective variable type to string.
    ///
    /// \param pObject
    ///   Pointer to an object of the respective type.
    ///
    /// \param szStr
    ///   String representation of the object (output).
    virtual void ObjectValueToString(const void* pObject, char* szStr) = 0;
  };

  /// \brief
  ///   Return the name of the variable
  inline const char *GetName() const {return (name != NULL) ? name : "";}

  /// \brief
  ///   Returns the string used as the display name in GUIs. Should NOT be used for identifying objects (ie. serialization).
  inline const char* GetDisplayName () const { return m_szDisplayName != NULL ? m_szDisplayName : name; }

  ///
  /// @name Access per-instance variable values
  /// @{
  ///

  /// \brief
  ///   Get the current variable value as set in the passed object. The value is written to the passed string, e.g. "0.01" for a float type variable
  ///
  /// \param obj
  ///   The instance to retrieve the variable value from. Should be an instance of class derived from VTypedObject
  /// \param str
  ///   The target string buffer to write the value
  /// \param bClassObject
  ///   Deprecated; should be true
  VBASE_IMPEXP void GetValue(void *obj,char *str,bool bClassObject = true);

  /// \brief
  ///   Set the variable value on the passed object. The new value is passed as a string, e.g. "0.01" for a float type variable
  ///
  /// \param obj
  ///   The instance to modify. Should be an instance of class derived from VTypedObject
  /// \param str
  ///   The string buffer containing the value to set.
  /// \param bClassObject
  ///   Deprecated; should be true
  VBASE_IMPEXP void SetValue(void *obj,const char *str,bool bClassObject = true);

  /// \brief
  ///   Get the current variable value as set in the passed object. The value is copied directly into the passed memory pointer, e.g. it copies 4 bytes for a float type variable
  ///
  /// \param obj
  ///   The instance to retrieve the variable value from. Should be an instance of class derived from VTypedObject
  /// \param ptr
  ///   The target pointer to copy the variable value
  /// \param bClassObject
  ///   Deprecated; should be true
  VBASE_IMPEXP void GetValueDirect(void *obj,void *ptr,bool bClassObject = true);

  /// \brief
  ///   Setter counterpart for function GetValueDirect
  VBASE_IMPEXP void SetValueDirect(void *obj,void *ptr,bool bClassObject = true);

  /// \brief
  ///   Access the value as a float3 vector. Assumes the variable is of type int-, float- or double vector
  ///
  /// \param obj
  ///   The instance to retrieve the variable value from. Should be an instance of class derived from VTypedObject
  /// \param x
  ///   Receives the x component of the vector
  /// \param y
  ///   Receives the y component of the vector
  /// \param z
  ///   Receives the z component of the vector
  /// \param bClassObject
  ///   Deprecated; should be true
  VBASE_IMPEXP void GetVector(void *obj,float &x,float &y,float &z,bool bClassObject = true);

  /// \brief
  ///   Setter counterpart for function GetVector
  VBASE_IMPEXP void SetVector(void *obj,float x,float y,float z,bool bClassObject = true);

  /// \brief
  ///   Access a value at given index in a vector variable. Assumes the variable is of type int-, float- or double vector
  ///
  /// \param obj
  ///   The instance to retrieve the variable value from. Should be an instance of class derived from VTypedObject
  /// \param index
  ///   0-based component index (must be 0..2)
  /// \param str
  ///   Buffer to write the value to
  /// \param bClassObject
  ///   Deprecated; should be true
  VBASE_IMPEXP void GetIndexedValue(void *obj,int index, char *str,bool bClassObject = true);

  /// \brief
  ///   Setter counterpart for function GetIndexedValue
  VBASE_IMPEXP void SetIndexedValue(void *obj,int index, char *str,bool bClassObject = true);

  /// \brief
  ///   Resets the variable value to the default value defined in the variable definition
  ///
  /// \param obj
  ///   The instance to modify. Should be an instance of class derived from VTypedObject
  /// \param bClassObject
  ///   Deprecated; should be true
  VBASE_IMPEXP void LoadDefaultValue(void *obj,bool bClassObject = true);

  /// \brief
  ///   DEPRECATED internal function
  VBASE_IMPEXP bool IsDataOwnByVar();

  ///
  /// @}
  ///

  ///
  /// @name Enum variables
  /// @{
  ///

  /// \brief
  ///   Returns the number of enum values in case this variable is an enum
  VBASE_IMPEXP int GetEnumCount();

  /// \brief
  ///   Returns the name of enum item with index num. name must have enough space for MAX_NAMELEN+1 characters
  VBASE_IMPEXP void GetEnumField(int num,char *name);
  
  /// \brief
  ///   Returns the number of the enum item called "name", -1 if not found
  VBASE_IMPEXP int FindEnumField(const char *name);

  /// \brief  Equality operator. Checks just name and type!
  /// \param  other  The variable used for comparison.
  /// \return true if the variables are considered equivalent.
  inline bool operator==(const VisVariable_cl & other) const
  {
    return type==other.type&&(name==other.name||(name!=NULL&&other.name!=NULL&&strcmp(name, other.name)==0));
  };

  /// \brief  Not Equality operator. Checks just name and type!
  /// \param  other  The variable used for comparison.
  /// \return true if the variables are NOT considered equivalent.
  inline bool operator!=(const VisVariable_cl & other) const
  {
    return type!=other.type||(name!=other.name&&(name==NULL||other.name==NULL||strcmp(name, other.name)!=0));
  };

  ///
  /// @}
  ///

  ///
  /// @name global variable creation/deletion
  /// @{
  ///

  /// \brief
  ///   Global function to create a new variable instance
  static VBASE_IMPEXP VisVariable_cl* NewVariable(const char *name, const char *desc, int type, int offs, const char *def, VDisplayHintFlags_e hints, const char *szEditorHintStr, size_t extra=0, const char* szDisplayName = NULL);

  /// \brief
  ///   Global function to delete a variable instance
  static VBASE_IMPEXP void DeleteVariable(VisVariable_cl* pVariable);

  ///
  /// @}
  ///


};  
#endif // _AEVARIABLE_H_
